package org.video.common.application;





import com.xuggle.xuggler.*;
import com.xuggle.xuggler.demos.VideoImage;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;


import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;

public class VideoPlayer implements IVideoPlayer {
    private static VideoImage mScreen = null;

    public void playVideo(String filename){
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        if (!IVideoResampler.isSupported(
                IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION))
            throw new RuntimeException("you must install the GPL version" +
                    " of Xuggler (with IVideoResampler support) for " +
                    "this demo to work");

        IContainer container = IContainer.make();

        if (container.open(filename, IContainer.Type.READ, null) < 0)
            throw new IllegalArgumentException("could not open file: " + filename);

        int numStreams = container.getNumStreams();

        int videoStreamId = -1;
        IStreamCoder videoCoder = null;
        for(int i = 0; i < numStreams; i++)
        {
            IStream stream = container.getStream(i);
            IStreamCoder coder = stream.getStreamCoder();

            if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO)
            {
                videoStreamId = i;
                videoCoder = coder;
                break;
            }
        }
        if (videoStreamId == -1)
            throw new RuntimeException("could not find video stream in container: "
                    +filename);

        if (videoCoder.open() < 0)
            throw new RuntimeException("could not open video decoder for container: "
                    +filename);

        IVideoResampler resampler = null;
        if (videoCoder.getPixelType() != IPixelFormat.Type.BGR24)
        {
            resampler = IVideoResampler.make(videoCoder.getWidth(),
                    videoCoder.getHeight(), IPixelFormat.Type.BGR24,
                    videoCoder.getWidth(), videoCoder.getHeight(), videoCoder.getPixelType());
            if (resampler == null)
                throw new RuntimeException("could not create color space " +
                        "resampler for: " + filename);
        }

        openJavaWindow();

        IPacket packet = IPacket.make();
        long firstTimestampInStream = Global.NO_PTS;
        long systemClockStartTime = 0;
        while(container.readNextPacket(packet) >= 0)
        {
            if (packet.getStreamIndex() == videoStreamId)
            {
                IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(),
                        videoCoder.getWidth(), videoCoder.getHeight());

                int offset = 0;
                while(offset < packet.getSize())
                {
                    int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
                    if (bytesDecoded < 0)
                        throw new RuntimeException("got error decoding video in: "
                                + filename);
                    offset += bytesDecoded;

                    if (picture.isComplete())
                    {
                        IVideoPicture newPic = picture;
                        if (resampler != null)
                        {
                            newPic = IVideoPicture.make(resampler.getOutputPixelFormat(),
                                    picture.getWidth(), picture.getHeight());
                            if (resampler.resample(newPic, picture) < 0)
                                throw new RuntimeException("could not resample video from: "
                                        + filename);
                        }
                        if (newPic.getPixelType() != IPixelFormat.Type.BGR24)
                            throw new RuntimeException("could not decode video" +
                                    " as BGR 24 bit data in: " + filename);

                        if (firstTimestampInStream == Global.NO_PTS)
                        {

                            firstTimestampInStream = picture.getTimeStamp();

                            systemClockStartTime = System.currentTimeMillis();
                        } else {
                            long systemClockCurrentTime = System.currentTimeMillis();
                            long millisecondsClockTimeSinceStartofVideo =
                                    systemClockCurrentTime - systemClockStartTime;

                            long millisecondsStreamTimeSinceStartOfVideo =
                                    (picture.getTimeStamp() - firstTimestampInStream)/1000 /5;
                            final long millisecondsTolerance = 50;
                            final long millisecondsToSleep =
                                    (millisecondsStreamTimeSinceStartOfVideo -
                                            (millisecondsClockTimeSinceStartofVideo +
                                                    millisecondsTolerance));
                            if (millisecondsToSleep > 0)
                            {
                                try
                                {
                                    Thread.sleep(millisecondsToSleep);
                                }
                                catch (InterruptedException e)
                                {
                                    return;
                                }
                            }
                        }


                        BufferedImage javaImage = Utils.videoPictureToImage(newPic);
                        int rows = javaImage.getWidth();
                        int cols = javaImage.getHeight();
                        int type = CvType.CV_16UC1;

                        Mat img = new Mat();
                        byte[] pixels = ((DataBufferByte) javaImage.getRaster().getDataBuffer()).getData();
                        img.put(0,0, pixels);
                        updateJavaWindow(javaImage);
                    }
                }
            }
            else
            {
                do {} while(false);
            }

        }

        if (videoCoder != null)
        {
            videoCoder.close();
            videoCoder = null;
        }
        if (container !=null)
        {
            container.close();
            container = null;
        }
        closeJavaWindow();

    }



    private void updateJavaWindow(BufferedImage javaImage)
    {
        mScreen.setImage(javaImage);
    }

    private void openJavaWindow()
    {
        mScreen = new VideoImage();
    }

    private static void closeJavaWindow()
    {
        System.exit(0);
    }
}
